package shiyan3;

import java.util.ArrayList;
import java.util.List;

/**
 * SymmetricMatrix stores only the upper triangle (including diagonal) in a 1D
 * array.
 * Indices are 1-based externally. Internally we map (i, j) with i <= j to a
 * linear index.
 */
public class SymmetricMatrix {
    private final int dimension;
    private final double[] data; // length = n*(n+1)/2

    public SymmetricMatrix(int n) {
        if (n <= 0) {
            throw new IllegalArgumentException("Dimension must be positive");
        }
        this.dimension = n;
        this.data = new double[n * (n + 1) / 2];
    }

    public int size() {
        return dimension;
    }

    /**
     * Set value at (row, col). For symmetry, value at (col, row) is implicitly the
     * same.
     */
    public void set(int row1Based, int col1Based, double value) {
        validateIndices(row1Based, col1Based);
        int i = row1Based - 1;
        int j = col1Based - 1;
        int idx = linearIndex(i, j);
        data[idx] = value;
    }

    /**
     * Get value at (row, col).
     */
    public double get(int row1Based, int col1Based) {
        validateIndices(row1Based, col1Based);
        int i = row1Based - 1;
        int j = col1Based - 1;
        int idx = linearIndex(i, j);
        return data[idx];
    }

    /**
     * Find all coordinates that equal the target value.
     * Returns a list of int[]{row, col}, both 1-based, covering the full matrix (i
     * and j all positions).
     */
    public List<int[]> findAll(double target) {
        List<int[]> positions = new ArrayList<>();
        for (int i = 0; i < dimension; i++) {
            for (int j = 0; j < dimension; j++) {
                if (Double.compare(get(i + 1, j + 1), target) == 0) {
                    positions.add(new int[] { i + 1, j + 1 });
                }
            }
        }
        return positions;
    }

    /**
     * Matrix addition: returns a new SymmetricMatrix = this + other.
     */
    public SymmetricMatrix add(SymmetricMatrix other) {
        if (other == null || other.dimension != this.dimension) {
            throw new IllegalArgumentException("Dimension mismatch");
        }
        SymmetricMatrix result = new SymmetricMatrix(dimension);
        for (int k = 0; k < data.length; k++) {
            result.data[k] = this.data[k] + other.data[k];
        }
        return result;
    }

    /**
     * Print the complete matrix in dense form.
     */
    public void printMatrix() {
        System.out.println("对称矩阵（" + dimension + " x " + dimension + "）：");
        for (int i = 0; i < dimension; i++) {
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < dimension; j++) {
                sb.append(String.format("%8.2f", get(i + 1, j + 1)));
            }
            System.out.println(sb);
        }
    }

    /**
     * Print basic info and storage description.
     */
    public void printInfo() {
        System.out.println("对称矩阵信息：");
        System.out.println("- 矩阵维度： " + dimension);
        System.out.println("- 存储元素个数（含对角的上三角）： " + data.length);
        System.out.println("- 存储方式：仅存上三角（i<=j）并压入一维数组，长度 n(n+1)/2");
    }

    private void validateIndices(int row1Based, int col1Based) {
        if (row1Based < 1 || row1Based > dimension || col1Based < 1 || col1Based > dimension) {
            throw new IndexOutOfBoundsException("Indices out of bounds: (" + row1Based + ", " + col1Based + ")");
        }
    }

    /**
     * Map (i, j) 0-based to linear index with i<=j by swapping when needed.
     * Compact formula for upper-triangular packing by rows:
     * index(i,j) = i*n - i*(i-1)/2 + (j - i) where 0<=i<=j<n
     */
    private int linearIndex(int i, int j) {
        if (i > j) {
            int t = i;
            i = j;
            j = t;
        }
        return i * dimension - (i * (i - 1)) / 2 + (j - i);
    }
}
